<?php

class bobMenuBar extends GtkMenuBar {

	public $item = array();
	public $root;

	public function __construct($define = array()) {
		parent::__construct();

		$this->signalRoot = $this->connect_simple(
			'map',
			array('bob','digRootUp'),
			$this
		);

		foreach($define as $iid => $item) {
			switch($item['type']) {
				case('break'): {
					$this->item[$iid] = new GtkSeparatorMenuItem;
					$this->item[$iid]->show();

					if($item['parent']) {
						$this->item[$item['parent']]->add($this->item[$iid]);
					} else {
						$this->item($this->item[$iid]);
					}
					
					break;
				}
				case('header'): {
					$this->item[$iid] = new GtkMenuItem($item['text']);
					$this->item[$iid]->show();

					if(array_key_exists('align',$item) && $item['align'] = 'right') {
						$this->item[$iid]->set_right_justified(true);
					}
					
					$this->item[$iid]->set_sensitive(false);
					
					if($item['parent']) {
						$this->item[$item['parent']]->add($this->item[$iid]);
					} else {
						$this->item($this->item[$iid]);
					}
					
					break;
				}
				case('item'): {
					$this->item[$iid] = new GtkMenuItem($item['text']);
					$this->item[$iid]->show();

					if(array_key_exists('align',$item) && $item['align'] = 'right') {
						$this->item[$iid]->set_right_justified(true);
					}
					
					if($item['parent']) {
						$this->item[$item['parent']]->add($this->item[$iid]);
					} else {
						$this->item($this->item[$iid]);
					}
					
					break;
				}

				case('menu'): {
					$this->item[$iid] = new GtkMenuItem($item['text']);
					$this->item[$mid = "{$iid}-bobMenu"] = new GtkMenu;
					$this->item[$iid]->set_submenu($this->item[$mid]);
					
					$this->item[$iid]->show();
					$this->item[$mid]->show();				

					if(array_key_exists('align',$item) && $item['align'] = 'right') {
						$this->item[$iid]->set_right_justified(true);
					}
				
					if($item['parent']) {
						$this->item[$item['parent']]->add($this->item[$iid]);
					} else {
						$this->add($this->item[$iid]);
					}
					
					unset($mid);
					break;
				}

				case('time'): {
					$this->item[$iid] = new bobMenuTimeBar;
					$this->item[$iid]->show();

					if(array_key_exists('align',$item) && $item['align'] = 'right') {
						$this->item[$iid]->set_right_justified(true);
					}
				
					if($item['parent']) {
						$this->item[$item['parent']]->add($this->item[$iid]);
					} else {
						$this->add($this->item[$iid]);
					}
					
					break;
				}

				case('recent-list'): {
					$this->item[$iid] = new bobRecentFileMenuItemList($this);

					foreach($this->item[$iid]->list as $iter => $menuitem) {
						$this->item[$item['parent']]->add($menuitem);
					}
					
					$this->item[$iid]->update();
					
					break;
				}

				case('eol-list'): {
					$this->item[$iid] = new bobLineEndingMenuItem($this);

					if($item['parent']) {
						$this->item[$item['parent']]->add($this->item[$iid]);
					} else {
						$this->add($this->item[$iid]);
					}
							
					break;
				}
				
			}
			
			if(array_key_exists('action',$item) && $item['action']) {
				if(is_array($item['action']) && count($item['action']) == 3) {
					$data = $item['action'][2];
					unset($item['action'][2]);
				} else {
					$data = null;
				}
				
				$this->item[$iid]->connect_simple('activate',$item['action'],$data);
			}
		}
		
		$this->show();
		return;
	}
}

class bobToolBar extends GtkToolBar {
	public function __construct($define) {
		parent::__construct();
		
		$this->btn = array();

		foreach($define as $iid => $item) {
			switch($item['type']) {
				case('togglebutton'): {
					$this->btn[$iid] = new GtkToggleToolButton;
					$this->btn[$iid]->set_label_widget(
						((substr($item['icon'],0,3) == 'gtk')?
							(GtkImage::new_from_stock($item['icon'],Gtk::ICON_SIZE_LARGE_TOOLBAR)):
							(GtkImage::new_from_file($item['icon'])))
					);
					break;
				}
				case('button'): {
					$this->btn[$iid] = new GtkToolButton(
						((substr($item['icon'],0,3) == 'gtk')?
							(GtkImage::new_from_stock($item['icon'],Gtk::ICON_SIZE_LARGE_TOOLBAR)):
							(GtkImage::new_from_file($item['icon']))),
						$item['text']					
					);
					break;
				}
				case('line-jump-bar'): {
					$this->btn[$iid] = new GtkToolItem;
					$this->btn["{$iid}-bobLineJump"] = new bobLineJumpBar;
					$this->btn[$iid]->add($this->btn["{$iid}-bobLineJump"]);
					break;
				}
				case('quickops'): {
					$this->btn[$iid] = new GtkMenuToolButton(
						((substr($item['icon'],0,3) == 'gtk')?
							(GtkImage::new_from_stock($item['icon'],Gtk::ICON_SIZE_LARGE_TOOLBAR)):
							(GtkImage::new_from_file($item['icon']))),
						'Quick Options'
					);
					
					$this->btn[$iid]->set_menu(new bobQuickOptionsBar);
					break;
				}
				case('adjust-margin-bar'): {
					$this->btn[$iid] = new GtkToolItem;
					$this->btn["{$iid}-bobAdjustMargin"] = new bobAdjustMarginBar;
					$this->btn[$iid]->add($this->btn["{$iid}-bobAdjustMargin"]);
					break;
				}
				case('break'): {
					$this->btn[$iid] = new GtkSeparatorToolItem;
					break;
				}
				case('divide'): {
					$this->btn[$iid] = new GtkSeparatorToolItem;
					$this->btn[$iid]->set_draw(false);
					$this->btn[$iid]->set_expand(true);
					break;
				}
			}

			if(array_key_exists('action',$item) && $item['action']) {
				switch($item['type']) {
					case('line-jump-bar'): {
						$this->btn["{$iid}-bobLineJump"]->entry->connect_simple('activate',$item['action']);
						break;
					}
					case('adjust-margin-bar'): {
						$this->btn["{$iid}-bobAdjustMargin"]->spin->connect_simple('value-changed',$item['action']);
						break;
					}
					default: {
						$this->btn[$iid]->connect_simple('clicked',$item['action']);
						break;
					}
				}				
			}

			$this->add($this->btn[$iid]);
		}
				
		$this->show_all();
		return;
	}
}

class bobStatusBar extends GtkVBox {

	public $timeout_main,$timeout_viewer;

	public function __construct() {
		parent::__construct();

		$this->hbox = new GtkHBox;
		$this->sidebar = new GtkButton('Sidebar');
		$this->main = new bobStatusLabel;
		$this->viewer = new bobStatusLabel;

		$this->root = null;
		$this->signalRoot = $this->connect_simple(
			'map',
			array('bob','digRootUp'),
			$this,
			array($this,'on_initialize')
		);
		
		$this->clear('main');
		
		$this->sidebar->set_focus_on_click(false);
		$this->main->set_padding(2,0);
//		$this->main->set_ellipsize(PANGO::ELLIPSIZE_MIDDLE);
		$this->viewer->set_padding(2,0);
	
		$this->hbox->pack_start($this->main,false,false,1);
//		$this->hbox->pack_end($this->sidebar,false,false,1);
		$this->hbox->pack_end($this->viewer,false,false,1);
		$this->pack_start($this->hbox,true,true,1);	
		$this->show_all();
		return;
	}
	
	public function message($where,$text = '',$timeout = true) {
		
		$this->{$where}->set_markup($text);
		bob::runUI();
	
		$tprop = "timeout_{$where}";

		if($timeout === true) {
			if($this->{$tprop}) {
				Gtk::timeout_remove($this->{$tprop});
				$this->{$tprop} = null;
			}
			
			$this->{$tprop} = Gtk::timeout_add(5000,array($this,'clear'),$where);
		}
		
		return;		
	}
	
	public function clear($widget = 'main') {
		if($widget == 'main') {
			$this->{$widget}->set_markup(sprintf('%s v%s',PROGRAM,VERSION));
		} else {
			$this->{$widget}->set_text('');
		} return;
	}
	
	public function on_initialize() {
		$this->sidebar->connect_simple('clicked',array($this->root,'on_action_sidebar'));
	}
}

class bobSearchBar extends GtkVBox {

	const MATCH_ANY = 0;
	const MATCH_CASE = 1;
	
	const FROM_START = 0;
	const FROM_CURSOR = 1;

	public function __construct() {
		parent::__construct();
		
		$this->hbox = new GtkHBox;

		$this->label = new GtkLabel;
		$this->entry = GtkComboBoxEntry::new_text();
		$this->find = new GtkButton('Go');
		$this->close = new GtkButton;

		$this->update_history();

		$this->case = GtkComboBox::new_text();
		$this->case->get_model()->append(array('Match Any'));
		$this->case->get_model()->append(array('Match Case'));

//		$this->entire = GtkComboBox::new_text();
//		$this->entire->get_model()->append(array('Entire File'));
//		$this->entire->get_model()->append(array('From Cursor'));

		$this->direction = GtkComboBox::new_text();
		$this->direction->get_model()->append(array('Search Up'));
		$this->direction->get_model()->append(array('Search Down'));
		
		$this->label->set_markup('<b>Search For:</b>');
		$this->label->set_size_request(100,-1);
		$this->label->set_alignment(1,0.5);
		$this->close->set_relief(Gtk::RELIEF_NONE);
		$this->close->set_image(
			GtkImage::new_from_stock(Gtk::STOCK_CLOSE,Gtk::ICON_SIZE_MENU)
		);

		$this->case->connect_simple('changed',array($this,'on_change'),'search-case',$this->case);
//		$this->entire->connect_simple('changed',array($this,'on_change'),'search-from',$this->entire);		
		$this->direction->connect_simple('changed',array($this,'on_change'),'search-direction',$this->direction);

		$this->case->set_active((($value = bob::$config->get('search-case')) !== null)?($value):(0));
//		$this->entire->set_active((($value = bob::$config->get('search-from')) !== null)?($value):(0));
		$this->direction->set_active((($value = bob::$config->get('search-direction')) !== null)?($value):(1));
		
		$this->hbox->pack_start($this->label,false,false,3);
		$this->hbox->pack_start($this->entry,false,false,3);
		$this->hbox->pack_start($this->case,false,false,3);
//		$this->hbox->pack_start($this->entire,false,false,3);
		$this->hbox->pack_start($this->direction,false,false,3);
		$this->hbox->pack_start($this->find,false,false,3);
		$this->hbox->pack_end($this->close,false,false,3);
		
		$this->pack_start($this->hbox,true,true,3);
		$this->hbox->show_all();
		return;
	}
	
	public function on_change($key,$w) {
		bob::$config->set($key,$w->get_active());
		return;
	}
	
	public function query() {
		return $this->entry->child->get_text();
	}
	
	public function update_history() {
		$neu = $this->query();
		
		if(($key = array_search($neu,bob::$histSearch))) {
			unset(bob::$histSearch[$key]);
			array_unshift(bob::$histSearch,$neu);
			bob::$histSearch = array_values(bob::$histSearch);
		} else {
			array_unshift(bob::$histSearch,$neu);
		}

		if(count(bob::$histSearch) > 10) {
			array_pop(bob::$histSearch);
		}
		
		bob::$config->set(
			'search-history',
			bob::writeHistoryObject('search-history',bob::$histSearch)
		); bob::$config->save();	

		$this->entry->get_model()->clear();
		foreach(bob::$histSearch as $term) {
			if(!$term) { continue; }
			$this->entry->get_model()->append(array($term));
		}
		return;
	}
	
}

class bobReplaceBar extends GtkVBox {

	public function __construct() {
		parent::__construct();
		
		$this->hbox = new GtkHBox;

		$this->label = new GtkLabel;
		$this->entry = GtkComboBoxEntry::new_text();
		$this->run = new GtkButton('Run');
		$this->close = new GtkButton;
		
		$this->update_history();

		$this->type = GtkComboBox::new_text();
		$this->type->get_model()->append(array('Replace Next'));
		$this->type->get_model()->append(array('Replace All'));
	
		$this->label->set_markup('<b>Replace With:</b>');
		$this->label->set_size_request(100,-1);
		$this->label->set_alignment(1,0.5);
		$this->close->set_relief(Gtk::RELIEF_NONE);
		$this->close->set_image(
			GtkImage::new_from_stock(Gtk::STOCK_CLOSE,Gtk::ICON_SIZE_MENU)
		);

		$this->type->connect_simple('changed',array($this,'on_change'),'replace-type',$this->type);

		$this->type->set_active((($value = bob::$config->get('replace-type')) !== null)?($value):(0));
		
		$this->hbox->pack_start($this->label,false,false,3);
		$this->hbox->pack_start($this->entry,false,false,3);
		$this->hbox->pack_start($this->type,false,false,3);
		$this->hbox->pack_start($this->run,false,false,3);
		$this->hbox->pack_end($this->close,false,false,3);
		
		$this->pack_start($this->hbox,true,true,3);
		$this->hbox->show_all();
		return;
	}
	
	public function on_change($key,$w) {
		bob::$config->set($key,$w->get_active());
		return;
	}

	public function query() {
		return $this->entry->child->get_text();
	}
	
	public function update_history() {
		$neu = $this->query();
		
		if(($key = array_search($neu,bob::$histReplace))) {
			unset(bob::$histReplace[$key]);
			array_unshift(bob::$histReplace,$neu);
			bob::$histReplace = array_values(bob::$histReplace);
		} else {
			array_unshift(bob::$histReplace,$neu);
		}

		if(count(bob::$histReplace) > 10) {
			array_pop(bob::$histReplace);
		}
		
		bob::$config->set(
			'replace-history',
			bob::writeHistoryObject('replace-history',bob::$histReplace)
		); bob::$config->save();	

		$this->entry->get_model()->clear();
		foreach(bob::$histReplace as $term) {
			if(!$term) { continue; }
			$this->entry->get_model()->append(array($term));
		}
		return;
	}	
}

class bobLineJumpBar extends GtkHBox {
	public function __construct() {
		parent::__construct();
		
		$this->label = new GtkLabel;
		$this->label->set_markup('<b>Line Jump:</b>');
		$this->label->set_alignment(1,0.5);
		
		$this->entry = new GtkEntry;
		$this->entry->set_width_chars(5);
		
		$this->pack_start($this->label,false,false,3);
		$this->pack_start($this->entry,false,false,3);
		$this->show_all();		
		return;
	}
}

class bobAdjustMarginBar extends GtkHBox {
	public function __construct() {
		parent::__construct();
		
		$this->label = new GtkLabel;
		$this->label->set_markup('<b>Margin:</b>');
		$this->label->set_alignment(1,0.5);
		
		$this->spin = GtkSpinButton::new_with_range(0,1024,1);
		$this->spin->set_digits(0);
		$this->spin->set_width_chars(3);
		
		$this->pack_start($this->label,false,false,3);
		$this->pack_start($this->spin,false,false,3);
		$this->show_all();		
		return;
	}
}

class bobTabWidthBar extends GtkHBox {
	public function __construct() {
		parent::__construct();
		
		$this->label = new GtkLabel;
		$this->label->set_markup('<b>Tab Width:</b>');
		$this->label->set_alignment(1,0.5);
		
		$this->spin = GtkSpinButton::new_with_range(2,16,1);
		$this->spin->set_digits(0);
		$this->spin->set_width_chars(2);
		
		$this->pack_start($this->label,false,false,3);
		$this->pack_start($this->spin,false,false,3);
		$this->show_all();		
		return;
	}
}

class bobMenuTimeBar extends GtkMenuItem {
	public function __construct() {
		parent::__construct('oh hi');
		$this->set_sensitive(false);
		$this->update();
		Gtk::timeout_add(10000,array($this,'update'));
		return;
	}
	
	public function update() {
		$this->child->set_label(date('D M j, Y H:i'));
		return true;
	}
}

class bobLineEndingBar extends GtkHBox {
	public function __construct() {
		parent::__construct();

		$this->label = new GtkLabel;
		$this->label->set_markup('<b>End of Line:</b>');
		$this->label->set_alignment(1,0.5);
		
		$this->drop = new bobLineEndingDropDown($this);

		$this->pack_start($this->label,false,false,3);
		$this->pack_start($this->drop,false,false,3);
		$this->show_all();		 
		return;
	}
}

/*//. class bobQuickOptionsBar
  ../ this bar will contain the widgets for setting some options quickly and
  ../ without dialogs. it also will manage the actions which take place on
  ../ the widgets inside, as the widgets themselves are dumb, manipulating the
  ../ window directly from the bar.
.//*/
class bobQuickOptionsBar extends GtkVBox {

	public $root;
	public $signalEOL,$signalTab,$signalMargin;

	public function __construct() {
		parent::__construct();

		$this->signalRoot = $this->connect_simple(
			'map',
			array('bob','digRootUp'),
			$this
		);

		$this->hbox = new GtkHBox;
		$this->label = new GtkLabel;
		$this->save = new GtkButton('Save Defaults');
		$this->margin = new bobAdjustMarginBar;
		$this->tab = new bobTabWidthBar;
		$this->eol = new bobLineEndingBar;
		
		$this->label->set_markup('<b>Quick Options</b>');
		
		$this->save->connect_simple(
			'clicked',
			array($this,'on_save_defaults')
		);
		
		$this->signalEOL = $this->eol->drop->connect_simple(
			'changed',
			array($this,'on_eol_change')
		);

		$this->signalTab = $this->tab->spin->connect_simple(
			'value-changed',
			array($this,'on_tab_change')
		);

		$this->signalMargin = $this->margin->spin->connect_simple(
			'value-changed',
			array($this,'on_margin_change')
		);

		$this->hbox->pack_start($this->label,false,false,3);
		$this->hbox->pack_end($this->save,false,false,3);
		$this->hbox->pack_end($this->margin,false,false,3);
		$this->hbox->pack_end($this->tab,false,false,3);
		$this->hbox->pack_end($this->eol,false,false,3);
		$this->hbox->show_all();
		$this->pack_start($this->hbox,true,true,3);
		return;
	}
	
	public function on_eol_change() {
		if(!is_object($this->root))
			return;
				
		$data = $this->eol->drop->get_model();
		$eol = $data->get_value(
			$this->eol->drop->get_active_iter(),
			0
		);
		
		$this->eol->drop->block($this->signalEOL);
		$this->root->on_eol_change($eol);
		bob::runUI();
		$this->eol->drop->unblock($this->signalEOL);
	
		return;
	}
	
	public function on_tab_change() {
		if(!is_object($this->root))
			return;
	
		$tab = $this->tab->spin->get_value();
		$this->root->on_tab_change($tab);		
		return;
	}
	
	public function on_margin_change() {
		if(!is_object($this->root))
			return;
	
		$margin = $this->margin->spin->get_value();
		$this->root->on_margin_change($margin);		
		return;
	}
	
	public function on_save_defaults() {
		if(!is_object($this->root))
			return;
		
		$tab = $this->tab->spin->get_value();
		$margin = $this->margin->spin->get_value();
		$eol = $this->eol->drop->get_model()->get_value(
			$this->eol->drop->get_active_iter(),
			0
		);
		
		bob::$config->set('end-of-line',$eol);
		bob::$config->set('tab-width',$tab);
		bob::$config->set('pos-right-margin',$margin);
	
		bob::$config->save();
		
		return;
	}
}

class bobSidebar extends GtkVBox {
	public function __construct() {
		parent::__construct();
		return;
	}
}

?>